/*
 * ota_updater.cpp
 *
 *  Created on: 2017-2-28
 *      Author: duanlian01
 */
#include "rda_ota_updater.h"
#include "baidu_iot_ota_log.h"
#include "rda5981_ota.h"
#include "rda_wdt_api.h"

const unsigned char ping_pong_copy_mode = 0x01;
const unsigned char ping_pong_switch_mode = 0x02;
const unsigned char boot_mode = ping_pong_copy_mode;
const unsigned int PAGE_SIZE = 1024;
char cache[PAGE_SIZE];
unsigned int left_size = 0;
unsigned int last_addr = 0;
unsigned int available_partition = 0;
int rda_notify_data_begin()
{
	  OTA_FUNC_ENTER();
	  memset(cache, 0xff, PAGE_SIZE);
	  left_size = 0;
	  last_addr = 0;
	  available_partition = 0;
	  OTA_FUNC_LEAVE();
    return 0;
}

int rda_notify_meta_data(void *cxt, struct package_meta_data *meta){
	int status = 0;
	struct rda_ota_update_context *context = (struct rda_ota_update_context*)cxt;
	OTA_FUNC_ENTER();
	if (context && meta && meta->install_info.module_count > 0)
	{
	    context->info = meta->install_info.module_list[0];
		const unsigned int upgrade_start_address = OTA_UPGRADE_ADDR;
		/*if (boot_mode == ping_pong_copy_mode)
		{
			upgrade_start_address = RDA5981_PARTITION_1_ADDR;
		}
		else if (boot_mode == ping_pong_switch_mode)
		{
		    upgrade_start_address = rda5981_get_next_partition_addr(RDA5981_PARTITION_0_ADDR, RDA5981_PARTITION_1_ADDR);
		}*/
		unsigned int upgrade_max_size = ((context->info.module_size)/4096 + 1)*4096;//PARTION_SIZE;
		if (upgrade_max_size > OTA_UPGRADE_AREA_SIZE)
		{
			OTA_LOG_ERR("upgrade size: 0x%x is greater than the max size:0x%x \n", upgrade_max_size, OTA_UPGRADE_AREA_SIZE);
			status = -1;
			return status;
		}
		context->address =  upgrade_start_address;   //write start position
		available_partition = upgrade_start_address;
		status = rda5981_write_partition_start(upgrade_start_address, upgrade_max_size);
        last_addr = 0;
		OTA_LOG_INFO("available parition address:0x%08x, start result:%d\n", available_partition, status);
	}
	OTA_FUNC_LEAVE();
	return status;
}

int rda_notify_module_data(void *cxt, unsigned int offset, unsigned char *data, unsigned int size)
{
	OTA_FUNC_ENTER();
	int status = -1;
	struct rda_ota_update_context *context = (struct rda_ota_update_context*)cxt;
	if (context && (last_addr + PAGE_SIZE) <= OTA_UPGRADE_AREA_SIZE)
	{

		  if ((left_size + size) < PAGE_SIZE)
			{
			    OTA_LOG_INFO("cache %d bytes from 0x%8x\n", size, (context->address + offset));
			    memcpy(cache + left_size, data, size);
				left_size += size;
				data += size;
				size = 0;
				status = 0;
			}
			else
			{
			      unsigned int copy = PAGE_SIZE - left_size;
				  memcpy(cache + left_size, data, copy);
				  status = rda5981_write_partition(last_addr, cache, PAGE_SIZE);
		          OTA_LOG_INFO("%d bytes written from 0x%8x, result:%d\n", PAGE_SIZE, last_addr,(int)status);
                  last_addr += PAGE_SIZE;

				  memcpy(cache, data + copy, size - copy);
				  left_size = size - copy;
				  data += size;
				  size = 0;
			}
	}
	OTA_FUNC_LEAVE();
	return status;
}

int rda_notify_data_end()
{
	OTA_FUNC_ENTER();
	int status = -1;
	if (left_size > 0) {
		if ((last_addr + PAGE_SIZE) <= OTA_UPGRADE_AREA_SIZE)
		{
	    	status = rda5981_write_partition(last_addr, cache, PAGE_SIZE);
		}
	} else {
		status = 0;
	}
	OTA_LOG_INFO("%d bytes written from 0x%8x, result:%d\n", left_size, last_addr,(int)status);

	rda5981_write_partition_end();
    OTA_FUNC_LEAVE();
	return status;
}

int rda_ota_update_image_begin()
{
    return 0;
}

void rda_ota_restart()
{
    OTA_FUNC_ENTER();
    rda_wdt_softreset();
	OTA_FUNC_LEAVE();
}

int rda_ota_update_image()
{
	OTA_FUNC_ENTER();
	//calculate crc, if something wrong happens, erase the content just written

	OTA_FUNC_LEAVE();
	return 0;
}

int rda_ota_update_image_end()
{
    return 0;
}
